using System.Collections.Generic;
using Kopernikus.Collections.Generic;

namespace Kopernikus.Parsing.GrammarSets
{
    public class CompressedGrammar
    {
        private readonly Set<Production> m_productions;
        private readonly Set<Production> m_startProductions;
        private Set<Production> m_compressedProductions;
        private Set<Production> m_compressedStartProductions;

        public CompressedGrammar(Set<Production> startProductions, Set<Production> productions)
        {
            m_startProductions = startProductions;
            m_productions = productions;
        }

        public Set<Production> CompressedStartProductions
        {
            get
            {
                Calculate();
                return m_compressedStartProductions;
            }
        }

        public Set<Production> CompressedProductions
        {
            get
            {
                Calculate();
                return m_compressedProductions;
            }
        }

        private void Calculate()
        {
            if (m_compressedStartProductions != null)
            {
                return;
            }

            Set<Symbol> symbols = new Set<Symbol>();
            m_compressedStartProductions = new Set<Production>();
            m_compressedProductions = new Set<Production>();

            foreach (Production p in m_startProductions)
            {
                Production pc = CompressProduction(symbols, p);
                m_compressedStartProductions.Add(pc);
                m_compressedProductions.Add(pc);
            }

            foreach (Production p in m_productions)
            {
                Production pc = CompressProduction(symbols, p);
                m_compressedProductions.Add(pc);
            }
        }

        private static Production CompressProduction(Set<Symbol> symbols, Production p)
        {
            List<Symbol> sl = new List<Symbol>();
            sl.Add(symbols.Add(p.LHS));
            foreach (Symbol s in p.RHS)
            {
                sl.Add(symbols.Add(s));
            }
            return new Production(sl);
        }
    }
}